/*
 * GLDevice.h
 *
 *  Created on: 2009/01/05
 *      Author: Yongshik Cho
 */

#ifndef GLDEVICE_H_
#define GLDEVICE_H_

#include <GL/glew.h>

#ifdef _WIN32
#include <GL/wglew.h>
#else
#include <GL/glxew.h>
#endif

// opengl
#ifdef __WXMAC__ //Mac
#	ifdef __DARWIN__
#		include <OpenGL/gl.h>
#		include <OpenGL/glaux.h>
#		include <OpenGL/glu.h>
#	else
#		include <gl.h>
#		include <glu.h>
#		include <glaux.h>
#	endif
#else
#	include <GL/gl.h>
#	include <GL/glu.h>
#	ifdef _WIN32
#		include <GL/glext.h>		//GL extensions
#		include <GL/wglext.h>		//WGL extensions
#	else
#		include <stdarg.h>
#		include <GL/glext.h>
#		include <GL/glx.h>
#	endif
#endif

#include <vector>

#ifndef PREREQUISITES_H_
#	include "../core/Prerequisites.h"
#endif

#ifndef RENDERDEVICE_H_
#	include "../RenderDevice.h"
#endif

#ifndef VECTOR2D_H
#	include "../core/Vector2D.h"
#endif

#ifndef VECTOR3D_H
#	include "../core/Vector3D.h"
#endif


struct VideoCaps
{
	int32	color;
	int32	alpha;
	int32	zBuffer;
	int32	accum;
	int32	stencil;
	int32	aaSamples;
	int32	hwAcc;
	GLboolean	sampleBuffer;
	GLboolean	doubleBuffer;
};


class GLDevice : public RenderDevice
{
public:
	static const std::string _GDI_Generic;
	static const std::string _GL_EXT_blend_color;
	static const std::string _GL_EXT_blend_func_separate;
	static const std::string _GL_EXT_blend_equation;
	static const std::string _GL_EXT_blend_minmax;
	static const std::string _GL_EXT_blend_subtract;

public:
	GLDevice(const HWND hWnd, const Rect2D& rect, DeviceSettings* sets);
	virtual ~GLDevice();

public:
	virtual void lookAt(const Vector3D& eye, const Vector3D& target, const Vector3D& up);
	virtual void setPerspective(const float aspect, const float fov, const float nearClip, const float farClip);
	virtual void setOrthogonal(const Camera* camera);

	virtual Texture* createTexture(const String& p, const uint32 width, const uint32 height,
			const uint32 orgWidth, const uint32 orgHeight, const uint32 rowBytes, const uint32 format, uint8* bitmap, uint8* orgBitmap);
	virtual void rebindTexture(Texture* tex, const uint32 format, uint8* bitmap);

	virtual void disposeTexture(Texture* texture);
	virtual void cleanupTextures();

	virtual const Vector3D fixCoordSystem(const Vector3D v);
	virtual const Quaternion fixCoordSystemQuat(const Quaternion q);

	virtual void clear(const Color& color);
	virtual void render(Renderable* r);
	virtual void drawQuadratic(const Rect2D& viewRect, Renderable* r);
	virtual void drawShape(ShapeObject* shape);
	virtual void drawParticle(ParticleObject* particle);
	virtual void drawRibbon(RibbonObject* ribbon);
	virtual void drawText(TextObject* text);
	virtual void drawCenter();
	virtual void drawRect(const Rect2D& r, const Color& color);
	virtual void drawLine(const Line2D& l, const Color& color);
	virtual void drawFillRect(const Rect2D& r, const Color& fillColor);
	virtual void drawPolygon(Polygon2D& poly, const Color& color);
	virtual void drawFillPolygon(Polygon2D& poly, const Color& fillColor);
	virtual void drawBezier(Curve2D& curve, const Color& color, uint32 stepCount = Curve2D::_DEFAULT_STEP_COUNT);
	virtual void drawFillBezier(Curve2D& curve, const Color& fillColor, uint32 stepCount = Curve2D::_DEFAULT_STEP_COUNT);
	virtual void drawPath(Path& path, const Color& color, uint32 stepCount = Curve2D::_DEFAULT_STEP_COUNT);
	virtual void drawPixels(const uint32 width, const uint32 height, const uint32 format, const uint8* ucbuf);
	virtual void drawCircle(Rect2D& r, Color& color);
	virtual void drawFillCircle(Rect2D& r, Color& fillColor);

	virtual const Vector2D getDevicePosition(const Vector2D& p);
	inline const Rect2D getDeviceRect(const Rect2D& r)
	{
		return Rect2D(getDevicePosition(r.mPoints[0]),
						getDevicePosition(r.mPoints[1]),
						getDevicePosition(r.mPoints[2]),
						getDevicePosition(r.mPoints[3]));
	}
	inline const float getViewAspect() const
	{
		return (float)mViewport.getWidth() / (float)mViewport.getHeight();
	}

	virtual void translate(const Vector2D& t);
	virtual void setMatrixMode(const uint32 mode);
	virtual void pushMatrix();
	virtual void popMatrix();

	void	swapBuffers();

public:
	virtual void onSize(const uint8 type, const Vector2D& size);

private:
	void init();
	void checkCaps();
	void enumDisplayModes();
	void setup();
	void setCurrent();
	GLint getInternalFormat();
	void enableByBlendType(const uint8 type);
	void disableByBlendType(const uint8 type);
	void setupBlendMode(const int32 blendMode);
	void drawQuad(Vector3D* vert, Vector2D* tex);
	void drawQuadStrip(Vector3D* vert, Vector2D* tex, size_t size);
	void drawOutlineText(TextObject* text);
	void drawOutline_Text(TextObject* text, const Vector2D trans, TTPOLYGONHEADER* header, uint32 size);
	void createTextBitmap(uint8* ucbuf);
	void drawControlPoint(const Rect2D& r);
	void drawCenterPoint(const Rect2D& r, const uint8 centerType);
	void drawCollidable(Renderable* r);
	void drawCollidablePoints(Renderable* r);
	void drawOrigin(Renderable* r);
	void drawAttachments(Renderable* r);

	static inline float float_from_fixed(FIXED f)
	{
		return (float)((f.fract >= 0x8000) ? (f.value + 1) : f.value);
	}

private:
	vector<VideoCaps> 	mVideoCapsList;
	VideoCaps			mVideoCaps;

	HWND				mWnd;
	HDC					mDC;
	HGLRC				mGLRC;

	int32				mPixelFormat;

	//device information
	std::string			mVendor;
	std::string			mVersion;
	std::string			mRenderer;
	std::string			mExtensions;

	Color				mClearColor;
	int32				mAnisofilterLevel;

	bool				mInitialized;

	bool				mHasHardware;
	bool				mHasSecondPass;

	bool				mIsSupportedAnisofilter;
	bool				mIsSupportedImaging;
	bool				mIsSupportedFragProg;
	bool				mIsSupportedVertexProg;
	bool				mIsSupportedGLSL;
	bool				mIsSupportedCompression;
	bool				mIsSupportedMultiTex;
	bool				mIsSupportedDrawRangeElements;
	bool				mIsSupportedPointSprites;
	bool				mIsSupportedAntiAlias;
	bool				mIsSupportedVBO;
	bool				mIsSupportedPBO;
	bool				mIsSupportedFBO;
	bool				mIsSupportedNPOT;
	bool				mIsSupportedOGL20;
	bool				mIsSupportedWGLPixelFormat;
	bool				mIsSupportedTexRects;
	bool				mIsSupportedMultisample;

	//definitions about extensions
	bool				mIsSupportedBlendColorEXT;
	bool				mIsSupportedBlendFuncSeparateEXT;
	bool				mIsSupportedBlendEquationEXT;
	bool				mIsSupportedBlendMinMaxEXT;
	bool				mIsSupportedBlendSubtractEXT;

};

#endif /* GLDEVICE_H_ */
